#!/usr/bin/env python

'''Deal with your release management by adding tags, doing archives, ...
'''

from mercurial import ui, repo, archival, config
import re
import tarfile, gzip, StringIO
from os import path, unlink
from time import time

_defaults = {
	'archive_path': '.',
	'archive_prefix': '',
	'tag_prefix': '',
	'version_basename': 'version'
}

def _getConfValue(ui, opts, key):
	'''Get the proper value of a configuration item in the current context
	
	Priority is : command line value -> hg configuration value -> value in _default mapping
	'''
	global _defaults
	if opts[key] != _defaults[key]:
		return opts[key]
	return ui.config('release', key, _defaults[key])

def release(ui, repo, **opts):
	'''Automatize tasks to easily release and share a revision of a repository

	The standard behaviour is to add a new tag to the repository by incrementing the last "versioning tag" (i.e. formatted like ``[text][number].[number]'') and then to create a gzipped tar archive of the versionned content.
	A file will be automatically added to the archive containing the created tag in order to allow the final user to know the version of his static content.
	'''

	_rev              = opts['rev']
	_major            = opts['major']
	_no_archive       = opts['no_archive']
	_archive_path     = _getConfValue(ui, opts, 'archive_path')
	_archive_prefix   = _getConfValue(ui, opts, 'archive_prefix')
	_no_tag           = opts['no_tag']
	_tag_prefix       = _getConfValue(ui, opts, 'tag_prefix')
	_version_basename = _getConfValue(ui, opts, 'version_basename')
	
	if _no_tag and _no_archive:
		ui.write_err("ERROR - You don't want to tag nor archive... why using this extension ?\n")
		return 1

	node = repo[_rev].node()

	if not _no_tag:
		# Retrieve the last version tag
		last_tag = 'v0.0'
		for tag,rev in repo.tagslist():
			if re.match('^[^\d]*\d+\.\d+$', tag):
				last_tag = tag
		ui.write('Last versioning tag was : %s\n' % last_tag)

		# Generate the new tag prefix
		tag_prefix = re.findall('^[^\d]*', last_tag)[0]
		if _tag_prefix != '':
			tag_prefix = _tag_prefix
	
		# Determine the new tag to create
		(major, minor) = re.findall('\d+', last_tag)
		major = int(major)
		minor = int(minor)
		if _major:
			major += 1
			minor = 0
		else:
			minor += 1
		new_tag = '%s%d.%d' % (tag_prefix, major, minor)
		ui.write('Create a new version : %s\n' % new_tag)
	
		# Be sure the user wants to continue, afterward modifications on the repo will be done...
		ans = ui.prompt('Do you want to continue [y|n] ?', 'n')
		if ans == 'n':
			ui.warn('User cancellation\n')
			return 0

		# Add the tag to the repository
		repo.tag(new_tag, local=False, message='** TAG NEW VERSION %s **' % new_tag, user=None, date=None, node=node)
	else:
		new_tag='rev%s:%s' % (repo[node].rev(), repo[node].hex()[:12])

	if not _no_archive:
		# Create a tar archive of versionned context
		archive_prefix = path.basename(repo.root)
		if _archive_prefix != '':
			archive_prefix = _archive_prefix
		archive_basename = archive_prefix+'-'+new_tag
		archive_filename = _archive_path+'/'+archive_basename+'.tar'
		archival.archive(repo, archive_filename, node, 'tar', prefix=archive_basename)
	
		# Add a version file to archive
		tar_archive = tarfile.TarFile(name=archive_filename, mode='a')
		version_file = tarfile.TarInfo(archive_basename+'/'+_version_basename)
		version_file.size = len(new_tag)
		version_file.mtime = time()
		tar_archive.addfile(version_file, StringIO.StringIO(new_tag))
		tar_archive.close()
		raw_archive = open(archive_filename, 'rb')
		compressed_archive = gzip.open(archive_filename+'.gz', mode='wb')
		compressed_archive.writelines(raw_archive)
		compressed_archive.close()
		raw_archive.close()
		unlink(archive_filename)
	

		ui.write('Archive %s.gz was successfully created\n' % archive_filename)
	
	return 0

cmdtable = {
	"release": (
		release, 
		[
			('r', 'rev', 'tip', 'Revision number to deal with'),
			('M', 'major', False, 'Indicates if this is a major release (otherwise will be a minor one)'),
			('', 'no-archive', False, 'Don\'t create an archive for the release'),
			('', 'archive-path', _defaults['archive_path'], 'Gives the root path where the archive will be created'),
			('', 'archive-prefix', _defaults['archive_prefix'], 'Prefix of the archive which will be created, you may want to give the convenient name of your project. If empty the name of the repository directory will be used.'),
			('', 'no-tag', False, 'Don\'t create a new tag for the release, use the existing one (or the revision number if none) instead'),
			('', 'tag-prefix', _defaults['tag_prefix'], 'Prefix of the tag to be created, by default it will retrieve the prefix of the last commited tag, if none it will be "v"'),
			('', 'version-basename', _defaults['version_basename'], 'Basename of the file to be created in the archive to contain the tag string')
		],
		"hg release [OPTIONS]"
	)
}
